#ifndef STATEMANAGER_H
#define STATEMANAGER_H

#include <map>
#include <vector>
#include <string>

#include "state.h"
#include "stateexception.h"

/**
 * Klasa zarzadcy stanow gry
 */
class StateManager
{
public:
	/**
	 * Zwraca zarzadce stanow
	 * @return Akutalny zarzadca stanow
	 */
	static StateManager& getInstance();

	/**
	 * Dodaje nowy stan do bazy stanow
	 * @param name Nazwa stanu, ktora bedzie identyfikowac stan w bazie
	 * @param stan Stan dodawany do bazy
	 * @throw GameStateException Wyjatek zwrcany, gdy podany identyfikator juz istnieje
	 */
	void registerState(const std::string name, State* state) throw(StateException);
	/**
	 * Usuwa stan z bazy stanow.
	 * @param name Nazwa stanu do usuniecia
	 * @return Wskazanie na wyrejetrowywany stan. Przyda sie aby moc go np. zniszczyć,
	 * niszczenie przy wyrejestrowywaniu mogloby byc troche niebezpieczne.
	 * Ogolnie potrzeba sprytnych wskaźników (patrz niżej)
	 * @throw GameStateException Wyjatek zwracany, gdy stan o podanym identyfikatorze nie istnieje.
	 */
	State* unregisterState(const std::string name) throw(StateException);
	/**
	 * Ustawia aktywany stan. Dodychczasowe stany na stosie zostaja zakonczone.
	 * @param name Identyfikator stanu do ustawienia.
	 * @throw GameStateException Wyjatek zwracany, gdy stan o podanym identyfikatorze nie istnieje.
	 */
	void setState(const std::string name) throw(StateException) ;
	/**
	 * Zwraca wskazanie na aktywnego stanu.
	 * @return Aktywnie wykonywany stan.
	 * @throw GameStateException Wyjatek zwracany, gdy nie ma aktualnie aktywnego stanu.
	 */
	State* getActiveState() throw(StateException);
	/**
	 * Wstawia stan na na stos stanow i go aktywuje.
	 * @param name Identyfikator stanu do dodania
	 * @throw GameStateException Wyjatek zwracany, gdy nie ma aktualnie aktywnego stanu.
	 */
	void pushState(const std::string name) throw(StateException);
	/**
	 * Usuwa aktywny stan ze stosu stanow. Jezeli na stosie sa inne stany, to aktywuje ostatnio wstrzymany.
	 * @throw GameStateException Wyjatek zwracany, gdy stos stanow jest pusty.
	 */
	void popState() throw(StateException);

private:
	/**
	 * Baza stanow.
	 * Wlasciwie stany powinny byc sprytnymi wskaznikami, kwestia czy zastosowac te z crystalspace,
	 * czy np. z boosta. Poki co trzeba pamietac o niszczeniu stanow na koncu programu
	 */
	std::map<std::string, State*> states_;
	/**
	 * Stos aktualnie wykonywanych stanow.
	 */
	std::vector<std::string> stack_;

	/**
	 * Prywatny konstruktor.
	 */
	StateManager() {}
	/**
	 * Prywatny konstruktor kopiujacy.
	 */
	StateManager(const StateManager&) {}

};

#endif // STATEMANAGER_H
